// ============================================
// internal/service/snapshot_service.go
// ============================================

package service

import (
	"context"
	"fmt"
	"time"

	"github.com/sirupsen/logrus"
	"libvirt.org/go/libvirt"
	"libvirt.org/go/libvirtxml"

	"virt-manager-go/internal/domain"
)

type snapshotService struct {
	connMgr   domain.ConnectionManager
	vmService domain.VMService
	logger    *logrus.Logger
}

func NewSnapshotService(connMgr domain.ConnectionManager, vmService domain.VMService, logger *logrus.Logger) domain.SnapshotService {
	return &snapshotService{
		connMgr:   connMgr,
		vmService: vmService,
		logger:    logger,
	}
}

// ListSnapshots 列出虚拟机所有快照
func (s *snapshotService) ListSnapshots(ctx context.Context, connID, vmName string) ([]*domain.SnapshotInfo, error) {
	dom, err := s.getDomain(connID, vmName)
	if err != nil {
		return nil, err
	}
	defer dom.Free()

	snapshots, err := dom.ListAllSnapshots(0)
	if err != nil {
		return nil, fmt.Errorf("failed to list snapshots: %w", err)
	}

	// 获取当前快照
	currentSnap, _ := dom.SnapshotCurrent(0)
	var currentName string
	if currentSnap != nil {
		currentName, _ = currentSnap.GetName()
		currentSnap.Free()
	}

	snapshotInfos := make([]*domain.SnapshotInfo, 0, len(snapshots))
	for _, snap := range snapshots {
		snapInfo, err := s.snapshotToInfo(&snap, currentName)
		snap.Free()
		if err != nil {
			s.logger.WithError(err).Warn("Failed to convert snapshot to info")
			continue
		}
		snapshotInfos = append(snapshotInfos, snapInfo)
	}

	return snapshotInfos, nil
}

// GetSnapshot 获取快照信息
func (s *snapshotService) GetSnapshot(ctx context.Context, connID, vmName, snapshotName string) (*domain.SnapshotInfo, error) {
	snap, currentName, err := s.getSnapshot(connID, vmName, snapshotName)
	if err != nil {
		return nil, err
	}
	defer snap.Free()

	return s.snapshotToInfo(snap, currentName)
}

// CreateSnapshot 创建快照
func (s *snapshotService) CreateSnapshot(ctx context.Context, connID, vmName string, config *domain.SnapshotConfig) (*domain.SnapshotInfo, error) {
	s.logger.WithFields(logrus.Fields{
		"connection": connID,
		"vm":         vmName,
		"snapshot":   config.Name,
	}).Info("Creating VM snapshot")

	dom, err := s.getDomain(connID, vmName)
	if err != nil {
		return nil, err
	}
	defer dom.Free()

	// 构建快照 XML
	xmlData, err := s.buildSnapshotXML(config)
	if err != nil {
		return nil, fmt.Errorf("failed to build snapshot XML: %w", err)
	}

	s.logger.WithField("xml", xmlData).Debug("Generated snapshot XML")

	// 设置快照标志
	flags := libvirt.DOMAIN_SNAPSHOT_CREATE_ATOMIC
	if config.Memory {
		// 内存快照（需要虚拟机运行）
		state, _, err := dom.GetState()
		if err != nil {
			return nil, fmt.Errorf("failed to get VM state: %w", err)
		}
		if state != libvirt.DOMAIN_RUNNING {
			return nil, fmt.Errorf("VM must be running for memory snapshot")
		}
	} else {
		flags |= libvirt.DOMAIN_SNAPSHOT_CREATE_DISK_ONLY
	}

	if config.Quiesce {
		flags |= libvirt.DOMAIN_SNAPSHOT_CREATE_QUIESCE
	}

	// 创建快照
	snap, err := dom.CreateSnapshotXML(xmlData, flags)
	if err != nil {
		return nil, fmt.Errorf("failed to create snapshot: %w", err)
	}
	defer snap.Free()

	s.logger.WithFields(logrus.Fields{
		"vm":       vmName,
		"snapshot": config.Name,
	}).Info("Snapshot created successfully")

	return s.snapshotToInfo(snap, config.Name)
}

// DeleteSnapshot 删除快照
func (s *snapshotService) DeleteSnapshot(ctx context.Context, connID, vmName, snapshotName string, deleteChildren bool) error {
	snap, _, err := s.getSnapshot(connID, vmName, snapshotName)
	if err != nil {
		return err
	}
	defer snap.Free()

	flags := libvirt.DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY
	if deleteChildren {
		flags |= libvirt.DOMAIN_SNAPSHOT_DELETE_CHILDREN
	}

	if err := snap.Delete(flags); err != nil {
		return fmt.Errorf("failed to delete snapshot: %w", err)
	}

	s.logger.WithFields(logrus.Fields{
		"vm":       vmName,
		"snapshot": snapshotName,
	}).Info("Snapshot deleted")

	return nil
}

// RevertToSnapshot 恢复到快照
func (s *snapshotService) RevertToSnapshot(ctx context.Context, connID, vmName, snapshotName string) error {
	s.logger.WithFields(logrus.Fields{
		"vm":       vmName,
		"snapshot": snapshotName,
	}).Info("Reverting to snapshot")

	snap, _, err := s.getSnapshot(connID, vmName, snapshotName)
	if err != nil {
		return err
	}
	defer snap.Free()

	flags := libvirt.DOMAIN_SNAPSHOT_REVERT_RUNNING | libvirt.DOMAIN_SNAPSHOT_REVERT_FORCE

	if err := snap.RevertToSnapshot(flags); err != nil {
		return fmt.Errorf("failed to revert to snapshot: %w", err)
	}

	s.logger.WithFields(logrus.Fields{
		"vm":       vmName,
		"snapshot": snapshotName,
	}).Info("Successfully reverted to snapshot")

	return nil
}

// GetCurrentSnapshot 获取当前快照
func (s *snapshotService) GetCurrentSnapshot(ctx context.Context, connID, vmName string) (*domain.SnapshotInfo, error) {
	dom, err := s.getDomain(connID, vmName)
	if err != nil {
		return nil, err
	}
	defer dom.Free()

	snap, err := dom.SnapshotCurrent(0)
	if err != nil {
		return nil, fmt.Errorf("no current snapshot: %w", err)
	}
	defer snap.Free()

	name, _ := snap.GetName()
	return s.snapshotToInfo(snap, name)
}

// === 辅助方法 ===

func (s *snapshotService) getDomain(connID, vmName string) (*libvirt.Domain, error) {
	conn, err := s.connMgr.GetConnection(connID)
	if err != nil {
		return nil, err
	}

	dom, err := conn.LookupDomainByName(vmName)
	if err != nil {
		return nil, fmt.Errorf("VM not found: %w", err)
	}

	return dom, nil
}

func (s *snapshotService) getSnapshot(connID, vmName, snapshotName string) (*libvirt.DomainSnapshot, string, error) {
	dom, err := s.getDomain(connID, vmName)
	if err != nil {
		return nil, "", err
	}
	defer dom.Free()

	snap, err := dom.SnapshotLookupByName(snapshotName, 0)
	if err != nil {
		return nil, "", fmt.Errorf("snapshot not found: %w", err)
	}

	// 获取当前快照名称
	currentSnap, _ := dom.SnapshotCurrent(0)
	var currentName string
	if currentSnap != nil {
		currentName, _ = currentSnap.GetName()
		currentSnap.Free()
	}

	return snap, currentName, nil
}

func (s *snapshotService) snapshotToInfo(snap *libvirt.DomainSnapshot, currentName string) (*domain.SnapshotInfo, error) {
	name, err := snap.GetName()
	if err != nil {
		return nil, err
	}

	// 解析快照 XML
	xmlData, err := snap.GetXMLDesc(0)
	if err != nil {
		return nil, err
	}

	snapConfig := &libvirtxml.DomainSnapshot{}
	if err := snapConfig.Unmarshal(xmlData); err != nil {
		return nil, err
	}

	snapInfo := &domain.SnapshotInfo{
		Name:        name,
		Description: snapConfig.Description,
		IsCurrent:   name == currentName,
		CreatedAt:   time.Now(),
	}

	if snapConfig.Parent != nil {
		snapInfo.Parent = snapConfig.Parent.Name
	}

	if snapConfig.State != "" {
		snapInfo.State = domain.SnapshotState(snapConfig.State)
	}

	if snapConfig.Memory != nil {
		snapInfo.Memory = snapConfig.Memory.Snapshot == "internal" || snapConfig.Memory.Snapshot == "external"
	}

	// 获取子快照
	children, err := snap.ListAllChildren(0)
	if err == nil {
		for _, child := range children {
			childName, _ := child.GetName()
			snapInfo.Children = append(snapInfo.Children, childName)
			child.Free()
		}
	}

	return snapInfo, nil
}

func (s *snapshotService) buildSnapshotXML(config *domain.SnapshotConfig) (string, error) {
	snapConfig := &libvirtxml.DomainSnapshot{
		Name:        config.Name,
		Description: config.Description,
	}

	if config.Memory {
		snapConfig.Memory = &libvirtxml.DomainSnapshotMemory{
			Snapshot: "internal",
		}
	} else if config.DiskOnly {
		snapConfig.Memory = &libvirtxml.DomainSnapshotMemory{
			Snapshot: "no",
		}
	}

	return snapConfig.Marshal()
}
